package com.gmrz.uaf.protocol.v1.processor;

import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.common.UAFException;
import com.gmrz.uaf.db.DAOException;
import com.gmrz.uaf.policy.verification.PolicyVerificationException;
import com.gmrz.uaf.policy.verification.StepupPolicyProcessor;
import com.gmrz.uaf.protocol.v1.processor.exception.AuthenticatorNotRegisteredException;
import com.gmrz.uaf.protocol.v1.processor.exception.PolicyNotFoundException;
import com.gmrz.uaf.protocol.v1.processor.exception.TxnContentCreationException;
import com.gmrz.uaf.protocol.v1.processor.exception.UAFErrorCode;
import com.gmrz.uaf.protocol.v1.schema.AuthenticationRequest;
import com.gmrz.uaf.protocol.v1.schema.Authenticator;
import com.gmrz.uaf.protocol.v1.schema.Policy;
import com.gmrz.uaf.protocol.v1.schema.ServerChallenge;
import com.gmrz.uas.plugin.exception.PluginException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.*;

public class UAFAuthInitProcessor extends UAFBaseProcessor {

    private static final Logger LOG = LogManager.getLogger(UAFAuthInitProcessor.class);

    public List<AuthenticationRequest> request(String custNo, String hashedUserName, String appID, String deviceID, List<String> authType,
                                               String transType, String transactionText, byte[] challengeParam, String ext)
            throws PolicyNotFoundException, TxnContentCreationException, DAOException,
            AuthenticatorNotRegisteredException,
            PolicyVerificationException, PluginException {
        Map<String, Object> map = getAuthenticationRequest(custNo, hashedUserName, appID, deviceID, authType, transType, transactionText, challengeParam, ext);
        List requests = new ArrayList();
        requests.add(map.get("request"));
        return requests;
    }

    // 获取客户端传递信息
    protected Map<String, Object> getAuthenticationRequest(String custNo, String hashedUserName, String appID, String deviceID, List<String> authType,
                                                           String transType, String transactionText, byte[] challengeParam, String ext)
            throws PolicyNotFoundException, TxnContentCreationException, DAOException,
            AuthenticatorNotRegisteredException,
            PolicyVerificationException {

        AuthenticationRequest request = GuiceUtil.getProcessorInjector().getInstance(AuthenticationRequest.class);

        // 生成随机挑战值
        byte[] challenge = getRandom(32);
        challenge = ArrayUtils.addAll(challenge, challengeParam);

        Policy p = null;
        Set<Authenticator> registeredList = null;
        String t_authType = null;
        for (String auth : authType) {
            // 获取策略
            p = this.policyManager.getNamedPolicy(auth, appID, transType);
            if (p == null) {
                continue;
            }
            // 获取已经注册的认证数据列表
            registeredList = getAuthenticatorListForAlreadyRegistered(hashedUserName, appID, deviceID,
                    auth, transType);
            if ((registeredList == null) || (registeredList.isEmpty())) {
                continue;
            }
            t_authType = auth;
        }
        if (p == null) {
            LOG.error("Requested policy {} is not available on server", "POLICY_" + appID + "_" + authType);
            throw new PolicyNotFoundException(UAFErrorCode.BIZ_POLICY_NOT_FOUND);
        }

        if ((registeredList == null) || (registeredList.isEmpty())) {
            throw new AuthenticatorNotRegisteredException(UAFErrorCode.BIZ_AUTHENTICATOR_NOT_FOUND);
        }
        // 过滤下策略数据，得到最终的策略数据
        StepupPolicyProcessor.filterPolicy(p, registeredList);

        // 将挑战值、策略名、原用户名放入 ServerData 中
        request.getOperationHeader().getServerData().withChallenge(challenge).withPolicyName(p.getPolicyName())
                .withUserName(custNo);
        request.getOperationHeader().setApplicationID(this.getServerConfig().getApplicationID(appID,transType));
        request.setServerChallenge(new ServerChallenge().withChallenge(challenge));
        request.setPolicy(p);
        if (transactionText != null) {
            try {
                // 将交易内容放入请求响应中
                request.setTransactions(TransactionContentProcessor.create(hashedUserName, this.dbutil, transactionText,
                        request.getOperationHeader().getServerData(), this.cryptoEngine, appID, deviceID, t_authType, transType));
            } catch (Exception ex) {
                LOG.error("Failed to create the transaction from given transaction text[{}]",
                        transactionText, ex);
                if ((ex instanceof UAFException)) {
                    UAFException uafe = (UAFException) ex;
                    throw new TxnContentCreationException(uafe.getErrorCode());
                }
                throw new TxnContentCreationException(UAFErrorCode.PROTOCOL_TXN_CONTENT_CREATE_FAILED);
            }
        }
        if (serverConfig.getAppIdUrlBoolean(appID,transType)) {
            setFacetsAaid(request, appID);
        }

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("request", request);
        resultMap.put("t_authType", t_authType);
        resultMap.put("registeredList", registeredList);
        resultMap.put("policy", p);
        return resultMap;

    }
}
